#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::analyse() {
	programme();
	cout << "Syntaxe correcte." << endl;
	sauterSymCour("debut");
	seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
}


/********************************* STRUCTURES *********************************/
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::affectation() {
// <affectation> ::= <variable> = <expression>

	//sauterSymCour("<VARIABLE>");
	testerSymCour("<VARIABLE>");
	ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	expression();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expression() {
// <expression> ::= <facteur> { <opBinaire> <facteur> }

	facteur();
	while ( ls.getSymCour()=="+" || ls.getSymCour()=="-" || 
			ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		opBinaire();
		facteur();
	}
}

////////////////////////////////////////////////////////////////////////////////---> à vérifier !!!
void LecteurPhraseAvecTable::facteur() {
// <facteur> ::= <entier> | <variable> | <opUnaire> <expBool> | ( <expBool> )

	if ((ls.getSymCour()=="<VARIABLE>") || (ls.getSymCour()=="<ENTIER>"))
        {
                ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
        }
        else if (ls.getSymCour()=="-" || ls.getSymCour()=="non") {
            opUnaire();
            expBool();
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		expBool();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::relation()
//<relation> ::= <expression> { <opRel> <expression> } 
{
    
    expression();
 if (ls.getSymCour()=="==" || ls.getSymCour()=="!="
        ||  ls.getSymCour()=="<" || ls.getSymCour()=="<="
        || ls.getSymCour()==">" || ls.getSymCour()==">=")
        {
     opRel();                   // while(ls.getSymCour()=="'une op réel'")
     expression();
	}
 }



////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expBool()
//<expBool> ::= <termeBool> { <opOu> <termeBool> }
{
    termeBool();
    if (ls.getSymCour()=="ou") 
    {
        opOu();
       termeBool();
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable:: termeBool()
//<temrmeBool>::=<relation> {<opEt> <relation>}
{
    relation();
    if(ls.getSymCour()=="et")
    {
        opEt();
        relation();
    }
}



/******************************* INSTRUCTIONS *********************************/
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::seqInst() {
// <seqIns> ::= <inst> ; { <inst> ; }

	do {
		inst();
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="si" || ls.getSymCour()=="tantque" || ls.getSymCour()=="repeter" || ls.getSymCour()=="lire"|| ls.getSymCour()=="ecrire");
	// tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::inst() {
// <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter>

    if (ls.getSymCour()=="<VARIABLE>")
        affectation();
    else if(ls.getSymCour()=="si" )
    {
          instSi();
    }
    else if(ls.getSymCour()=="tantque")
    {
        instTq();
    }
    else if (ls.getSymCour()=="repeter")
    {
       instRepeter();
    }
    else if (ls.getSymCour()=="lire")
    {
       instLire();
    }
    else if (ls.getSymCour()=="ecrire")
    {
       instEcrire();
    }
    else if (ls.getSymCour()=="pour")
    {
        instPour();
    }
    else
	erreur("<inst>");
}



////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instSi(){
//      <instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> } [ sinon <seqInst> ] finsi
    
    sauterSymCour("si");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    sauterSymCour("alors");
    seqInst();
    
    while(ls.getSymCour()=="sinonsi")
    {
        ls.suivant();
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
        sauterSymCour("alors");
        seqInst();
    }
    
    sauterSymCour("sinon");
    seqInst();
    sauterSymCour("finsi");

   

}

////////////////////////////////////////////////////////////////////////////////
 void LecteurPhraseAvecTable::instTq(){
 //      <instTq> ::= tantque ( <expBool> ) <seqInst> fintantque
     
   
        sauterSymCour("tantque");
        sauterSymCour("(");
        expBool();
        sauterSymCour("(");
        seqInst();
        sauterSymCour("fintantque");
        
 }
 ////////////////////////////////////////////////////////////////////////////////
 void LecteurPhraseAvecTable::instRepeter(){
//      <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
     
     sauterSymCour("repeter");
     seqInst();
     sauterSymCour("jusqua");
     sauterSymCour("(");
     expBool();
     sauterSymCour("(");
     
 }
  ////////////////////////////////////////////////////////////////////////////////
 void LecteurPhraseAvecTable::instPour(){
//      <instPour> : pour (<affectation>;<expBool>; <affectation>) faire { <seqInst> } 
     
     sauterSymCour("pour");
     sauterSymCour("(");
     affectation();
     sauterSymCour(";");
     expBool();
     sauterSymCour(";");
     affectation();
     sauterSymCour(")");
     sauterSymCour("faire");
     sauterSymCour("{");
     seqInst();
     sauterSymCour("}");

  }
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instLire(){
  //  <instLire> ::= lire ( <variable> )
    
    sauterSymCour("lire");
    sauterSymCour("(");
    testerSymCour("<VARIABLE>");
	ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
    
    sauterSymCour(")");
    
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instEcrire(){
  //  <instEcrire> ::= ecrire ( <expression> | <chaine> )
    
    sauterSymCour("ecrire");
    sauterSymCour("("); 
    if(ls.getSymCour()=="<CHAINE>")
    {	ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
    }
    else expression();  
    sauterSymCour(")");  
    
}




/******************************** OPERATEURS **********************************/
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opBool()
// <opBool> ::= et | ou
{
	if (ls.getSymCour()=="et" || ls.getSymCour()=="ou")
        {	ls.suivant();
        }
	else
        {
		erreur("<opBool>");
        }
}
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opEt()
// <opEt> ::= et 
{
    if (ls.getSymCour()=="et")
    {
        ls.suivant();
    }
    else
        {
		erreur("<opEt>");
        }
}
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opOu()
// <opOu> ::= ou
{
        if (ls.getSymCour()=="ou")
    {
        ls.suivant();
    }
    else
        {
		erreur("<opOu>");
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opRel()
//<opRel> ::= == | != | < | <= | > | >=
{
    if (ls.getSymCour()=="==" || ls.getSymCour()=="!="
        ||  ls.getSymCour()=="<" || ls.getSymCour()=="<="
        || ls.getSymCour()==">" || ls.getSymCour()==">=" )
        {	ls.suivant();
        }
	else
        {
		erreur("<opRel>");
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opUnaire()
// <opUnaire> ::= - | non
{
    if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
    {
        ls.suivant();
    }
    else
        {
		erreur("<opUnaire>");
        }
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opAdd() {
// <opAdd> ::= + | -

	if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
		ls.suivant();
	else
		erreur("<opAdd>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opMult() {
// <opMult> ::= * | /

	if (ls.getSymCour()=="*" || ls.getSymCour()=="/")
		ls.suivant();
	else
		erreur("<opMult>");
}







////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::programme() {
// <programme> ::= debut <seqInst> fin <EOF>

	sauterSymCour("debut");
	seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opBinaire() {
// <opBinaire> ::= + | - | *  | /

	if (ls.getSymCour()=="+" || ls.getSymCour()=="-" || 
		ls.getSymCour()=="*" || ls.getSymCour()=="/" )
		ls.suivant();
	else
		erreur("<opBinaire>");
}




/********************************** AUTRES ************************************/
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
